import { User as PrismaUser } from "@prisma/client";
import prisma from "../config/database";
import { LoginUserDTO, UserListDTO, UserRole } from "../dtos/user.dto";
import {
  LoginRequestDTO,
  RegisterRequestDTO,
  UpdateUserRequestDTO,
} from "../validators/user.validator";
import { AuthUtil } from "../utils/auth.util";

export class UserService {
  public static availableUserIdList = new Set<number>();

  /*
   * 检查用户是否被禁用
   * @param userId 用户ID
   * @returns 是否被禁用
   */
  static async checkUserAvailable(userId: number): Promise<boolean> {
    if (!this.availableUserIdList.size) {
      await this.updateAvailableUserIdList();
    }
    return this.availableUserIdList.has(userId);
  }

  // 更新用户ID列表
  static async updateAvailableUserIdList() {
    const userList = await prisma.user.findMany({
      where: {
        isDisable: false,
      },
    });
    this.availableUserIdList = new Set(userList.map((user) => user.id));
  }

  /**
   * 用户注册业务逻辑
   * @param registerData 注册请求参数
   * @returns 注册成功的用户信息
   * @throws 业务异常（如手机号已存在）
   */
  public static async register(
    registerData: RegisterRequestDTO
  ): Promise<LoginUserDTO> {
    const { mobile, password, role } = registerData;

    // 1. 检查手机号是否已存在
    const existingUser = await prisma.user.findUnique({
      where: { mobile },
    });

    if (existingUser) {
      throw new Error("手机号已注册");
    }

    // 2. 密码加密
    const hashedPassword = await AuthUtil.hashPassword(password);

    // 3. 创建用户
    const user = await prisma.user.create({
      data: {
        name: registerData.name,
        mobile,
        password: hashedPassword,
        role: role.toLocaleLowerCase() as UserRole,
        isDisable: false,
      },
    });

    // 3. 更新可用用户ID列表
    await this.updateAvailableUserIdList();

    // 4. 返回脱敏后的用户信息
    return {
      id: user.id,
      name: user.name,
      mobile: AuthUtil.maskMobile(user.mobile),
      role: user.role as UserRole,
    };
  }

  /**
   * 更新用户信息
   * @param userId 用户ID
   * @param updateData 更新数据
   * @returns 更新后的用户信息
   * @throws 业务异常（如用户不存在、手机号已存在）
   */
  public static async updateUser(
    userId: number,
    updateData: UpdateUserRequestDTO
  ): Promise<LoginUserDTO> {
    // 1. 检查用户是否存在
    const existingUser = await prisma.user.findUnique({
      where: { id: userId },
    });

    if (!existingUser) {
      throw new Error("用户不存在");
    }

    // 2. 如果更新手机号，检查手机号是否已被其他用户使用
    if (updateData.mobile && updateData.mobile !== existingUser.mobile) {
      const userWithSameMobile = await prisma.user.findUnique({
        where: { mobile: updateData.mobile },
      });

      if (userWithSameMobile && userWithSameMobile.id !== userId) {
        throw new Error("手机号已被其他用户使用");
      }
    }

    // 3. 准备更新数据
    const updatePayload: any = { ...updateData };

    // 处理密码加密
    if (updateData.password) {
      updatePayload.password = await AuthUtil.hashPassword(updateData.password);
    }

    // 处理角色字段格式
    if (updateData.role) {
      updatePayload.role = updateData.role.toLocaleLowerCase() as UserRole;
    }

    // 4. 更新用户
    const updatedUser = await prisma.user.update({
      where: { id: userId },
      data: updatePayload,
    });

    // 如果修改了isDisable字段，则更新可用用户ID列表
    if (updateData.isDisable !== undefined) {
      await this.updateAvailableUserIdList();
    }

    // 5. 返回脱敏后的用户信息
    return {
      id: updatedUser.id,
      name: updatedUser.name,
      mobile: AuthUtil.maskMobile(updatedUser.mobile),
      role: updatedUser.role as UserRole,
    };
  }

  /**
   * 登录业务逻辑
   * @param loginData 登录请求参数（来自Controller层）
   * @returns 脱敏后的用户信息（供Controller层签发token）
   * @throws 业务异常（如手机号不存在、密码错误、用户禁用）
   */
  public static async login(loginData: LoginRequestDTO): Promise<LoginUserDTO> {
    const { mobile, password } = loginData;
    // 1. 按手机号查询用户（PrismaUser类型：数据库原始数据）
    const user: PrismaUser | null = await prisma.user.findUnique({
      where: { mobile },
    });

    // 2. 校验用户是否存在
    if (!user) {
      throw new Error("手机号不存在");
    }

    // 3. 校验用户是否禁用
    if (user.isDisable) {
      throw new Error("账号已禁用，请联系管理员");
    }

    // 4. 比对密码（明文密码 vs 数据库加密密码）
    const isPasswordValid: boolean = await AuthUtil.comparePassword(
      password,
      user.password
    );
    if (!isPasswordValid) {
      throw new Error("密码错误");
    }

    // 5. 脱敏处理（PrismaUser → LoginUserDTO）
    const maskedUser: LoginUserDTO = {
      id: user.id,
      name: user.name,
      mobile: AuthUtil.maskMobile(user.mobile), // 调用工具类脱敏
      role: user.role as UserRole, // 类型断言，避免类型错误
    };

    return maskedUser;
  }

  /**
   * 获取用户列表（需要管理员权限）
   * @returns 用户列表
   */
  public static async listUsers(): Promise<UserListDTO> {
    const users = await prisma.user.findMany();
    return users.map((user) => ({
      id: user.id,
      name: user.name,
      mobile: AuthUtil.maskMobile(user.mobile),
      role: user.role as UserRole,
      isDisable: user.isDisable,
    }));
  }

  /**
   * 删除用户（需要管理员权限）
   * @param userId 用户ID
   * @throws 业务异常（如用户不存在）
   */
  public static async deleteUser(userId: number): Promise<void> {
    // 1. 检查用户是否存在
    const existingUser = await prisma.user.findUnique({
      where: { id: userId },
    });

    if (!existingUser) {
      throw new Error("用户不存在");
    }

    // 2. 删除用户
    await prisma.user.delete({
      where: { id: userId },
    });

    // 3. 更新可用用户ID列表
    await this.updateAvailableUserIdList();
  }

  /**
   * 禁用/启用用户
   * @param userId 用户ID
   * @param isDisable 是否禁用
   * @returns 更新后的用户信息
   * @throws 业务异常（如用户不存在、状态已相同）
   */
  public static async toggleUserStatus(
    userId: number,
    isDisable: boolean
  ): Promise<LoginUserDTO> {
    // 检查用户是否存在
    const user = await prisma.user.findUnique({
      where: { id: userId },
    });

    if (!user) {
      throw new Error("用户不存在");
    }

    if (user.isDisable === isDisable) {
      throw new Error(`用户已经是${isDisable ? "禁用" : "启用"}状态`);
    }

    // 更新用户状态
    const updatedUser = await prisma.user.update({
      where: { id: userId },
      data: { isDisable },
    });

    // 更新可用用户ID列表
    await this.updateAvailableUserIdList();

    return {
      id: updatedUser.id,
      name: updatedUser.name,
      mobile: AuthUtil.maskMobile(updatedUser.mobile),
      role: updatedUser.role as UserRole,
    };
  }

  // 修改用户密码
  public static async updatePassword(
    userId: number,
    oldPassword: string,
    newPassword: string
  ): Promise<void> {
    // 1. 检查用户是否存在
    const user = await prisma.user.findUnique({
      where: { id: userId },
    });

    if (!user) {
      throw new Error("用户不存在");
    }

    // 2. 校验旧密码是否匹配
    const isPasswordValid: boolean = await AuthUtil.comparePassword(
      oldPassword,
      user.password
    );
    if (!isPasswordValid) {
      throw new Error("旧密码错误");
    }

    // 3. 加密新密码
    const hashedNewPassword = await AuthUtil.hashPassword(newPassword);

    // 4. 更新用户密码
    await prisma.user.update({
      where: { id: userId },
      data: { password: hashedNewPassword },
    });
  }
}
